package ua.dogar.vectors;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;

import ua.dogar.exceptions.IncompatibleVectorSizesException;
import ua.dogar.exceptions.VectorIndexOutOfBoundsException;
import ua.dogar.patterns.Observer;



public class ArrayVector implements Vector {
	private double[] vector;
    private ArrayList arrVecObservers = new ArrayList();
	public ArrayVector(int length) {
		if(length>0)
		vector = new double[length];
		else
		System.out.println("Wrong length!");
	}

	public ArrayVector(double... values) {
		if(values!=null)
		vector = values;
		else
			System.out.println("Empty data");
	}

	@Override
	public double getElement(int index){
		if(index <0 || index>getLength()) throw new VectorIndexOutOfBoundsException(index);
		return vector[index];
	}

	@Override
	public void setElement(double value, int index) {
		if(index <0 || index>getLength()) throw new VectorIndexOutOfBoundsException(index);
		vector[index] = value;
		notifyObservers(index);
	}

	@Override
	public int getLength() {
		return vector.length;
	}

	@Override
	public void setElementsFromArray(double[] arr) throws IncompatibleVectorSizesException{
		if (arr!=null) {
			if(arr.length!=getLength()) throw new IncompatibleVectorSizesException();
			for (int i = 0; i < arr.length; i++)
				vector[i] = arr[i];
			notifyObservers();
		}

	}

	@Override
	public void setElementsFromVector(Vector v) throws IncompatibleVectorSizesException{
		if(v!=null){
			if(v.getLength()!=getLength()) throw new IncompatibleVectorSizesException();
			for (int i = 0; i < v.getLength(); i++)
				vector[i] = v.getElement(i);
			notifyObservers();		
		}
	}

	@Override
	public boolean compare(Vector v) {
		if(v!=null){
		if (v.getLength() == vector.length) { 
			for (int i = 0; i < v.getLength(); i++)
				if (vector[i] != v.getElement(i))
					return false;
			return true;
		} else
			return false;
		}
		else return false;
	}

	@Override
	public Vector mulVector(int num) {
		for (int i = 0; i < vector.length; i++)
			vector[i] = vector[i] * num;
		notifyObservers();
		return this;
	}

	@Override
	public void addVector(Vector v) throws IncompatibleVectorSizesException{
		if(v!=null){
			if(v.getLength()!=getLength()) throw new IncompatibleVectorSizesException();
			for (int i = 0; i < v.getLength(); i++)
				vector[i] = vector[i] + v.getElement(i);
			notifyObservers();
		}
	}

	@Override
	public String toString() {

		StringBuffer stringOut = new StringBuffer(); 
		stringOut.append("ArrayVector [vector=");
		stringOut.append(Arrays.toString(vector));
		stringOut.append("]");
		return stringOut.toString();
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (obj instanceof Vector) {
			Vector temp = (Vector) obj;
			if (temp.getLength() == getLength()) {
				for (int i = 0; i < getLength(); i++)
					if (temp.getElement(i) != this.getElement(i))
						return false;
				return true;
			}
		}
		return false;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		ArrayVector clone = (ArrayVector) super.clone();
		clone.vector = vector.clone();
		return clone;
	}

	@Override
	public int hashCode() {
		int result = 0;
		for (int i = 0; i < getLength(); i++) {
			long bits = Double.doubleToRawLongBits(getElement(i));
			result ^= ((int) (bits & 0x00000000FFFFFFFFL))
					^ ((int) ((bits & 0xFFFFFFFF00000000L)));
		}
		return result;
	}

	class myIterator implements Iterator<Double> {
		int counter = 0;

		@Override
		public boolean hasNext() {
			if (counter == vector.length)
				return false;
			else
				return true;
		}

		@Override
		public Double next() {
			if(!hasNext()) throw new NoSuchElementException();
			return getElement(counter++);
		}

		@Override
		public void remove() {

		}

	}

	@Override
	public Iterator<Double> iterator() {
		return new myIterator();
	}

	@Override
	public void registerObserver(Observer o) {
		arrVecObservers.add(o);
	}

	@Override
	public void removeObserver(Observer o) {
			int index = arrVecObservers.indexOf(o);
	        if (index>=0) arrVecObservers.remove(index);
	}

	@Override
	public void notifyObservers(int index) {
		for ( int i =0; i< arrVecObservers.size(); i++)
        {
            Observer observer = (Observer) arrVecObservers.get(i); 
            observer.updateIndex(index);
        }
	}

	@Override
	public void notifyObservers() {
		for ( int i =0; i< arrVecObservers.size(); i++)
        {
            Observer observer = (Observer) arrVecObservers.get(i); 
            observer.update(this);
        }
	}

}
